<template>
  <div
    ref="dragVerify"
    class="drag_verify"
    :style="dragVerifyStyle"
    @mousemove="dragMoving"
    @mouseup="dragFinish"
    @mouseleave="dragFinish"
    @touchmove="dragMoving"
    @touchend="dragFinish"
  >
    <div
      class="dv_progress_bar"
      :class="{ goFirst2: isOk }"
      ref="progressBar"
      :style="progressBarStyle"
    ></div>
    <div class="dv_text" :style="textStyle" ref="messageRef">
      <slot name="textBefore" v-if="$slots.textBefore"></slot>
      {{ message }}
      <slot name="textAfter" v-if="$slots.textAfter"></slot>
    </div>

    <div
      class="dv_handler dv_handler_bg"
      :class="{ goFirst: isOk }"
      @mousedown="dragStart"
      @touchstart="dragStart"
      ref="handler"
      :style="handlerStyle"
    >
      <el-icon><DArrowRight v-if="icon === 0" /><Check v-else /></el-icon>
    </div>
  </div>
</template>
<script setup lang="ts" name="DragVerify">
import type { Ref } from 'vue'

const props = defineProps({
  isPassing: {
    type: Boolean,
    default: false
  },
  width: {
    type: Number,
    default: 250
  },
  height: {
    type: Number,
    default: 40
  },
  text: {
    type: String,
    default: '请按住滑块，向右滑动验证'
  },
  successText: {
    type: String,
    default: '验证成功'
  },
  background: {
    type: String,
    default: 'rgba(235, 235, 235, 1)'
  },
  progressBarBg: {
    type: String,
    default: '#76c61d'
  },
  completedBg: {
    type: String,
    default: '#76c61d'
  },
  circle: {
    type: Boolean,
    default: false
  },
  radius: {
    type: String,
    default: '2px'
  },
  handlerIcon: {
    type: String
  },
  successIcon: {
    type: String
  },
  handlerBg: {
    type: String,
    default: 'rgba(255, 255, 255, 1)'
  },
  textSize: {
    type: String,
    default: '14px'
  },
  textColor: {
    type: String,
    default: 'rgba(107, 111, 128, 1)'
  }
})
const emit = defineEmits<{
  (e: 'handler-move'): void
  (e: 'update:isPassing', flag: boolean): void
  (e: 'passcallback'): void
}>()
const dragVerify = ref<HTMLDivElement>() as Ref<HTMLDivElement>
const handler = ref<HTMLDivElement>() as Ref<HTMLDivElement>
const progressBar = ref<HTMLDivElement>() as Ref<HTMLDivElement>
const messageRef = ref<HTMLDivElement>() as Ref<HTMLDivElement>

onMounted(() => {
  dragVerify.value?.style.setProperty('--text-color', props.textColor)
  dragVerify.value?.style.setProperty(
    '--width',
    Math.floor(props.width / 2) + 'px'
  )
  dragVerify.value?.style.setProperty(
    '--pwidth',
    -Math.floor(props.width / 2) + 'px'
  )
})
watch(
  () => props.isPassing,
  (newVal: boolean) => {
    if (!newVal) {
      restore()
    }
  }
)

const isMoving = shallowRef<boolean>(false)
const x = shallowRef<number>(0)
const isOk = shallowRef<boolean>(false)
const icon = shallowRef<number>(0)
const handerLeft = shallowRef<string>('0px')

const handlerStyle = computed(() => {
  return {
    left: handerLeft.value,
    width: props.height + 'px',
    height: props.height + 'px',
    background: props.handlerBg
  }
})
const message = computed(() => {
  return props.isPassing ? props.successText : props.text
})
const dragVerifyStyle = computed(() => {
  return {
    width: props.width + 'px',
    height: props.height + 'px',
    lineHeight: props.height + 'px',
    background: props.background,
    borderRadius: props.circle ? props.height / 2 + 'px' : props.radius
  }
})
const progressBarStyle = computed(() => {
  return {
    background: props.progressBarBg,
    height: props.height + 'px',
    borderRadius: props.circle
      ? props.height / 2 + 'px 0 0 ' + props.height / 2 + 'px'
      : props.radius
  }
})
const textStyle = computed(() => {
  return {
    height: props.height + 'px',
    width: props.width + 'px',
    fontSize: props.textSize
  }
})
const dragStart = (e: any) => {
  if (!props.isPassing) {
    isMoving.value = true
    x.value =
      (e.pageX || e.touches[0].pageX) -
      parseInt(handler.value?.style.left.replace('px', ''), 10)
  }
  emit('handler-move')
}

const dragMoving = (e: any) => {
  dragVerify.value!.onselectstart = function () {
    return false
  }
  if (isMoving.value && !props.isPassing) {
    const _x = (e.pageX || e.touches[0].pageX) - x.value
    if (_x > 0 && _x <= props.width - props.height) {
      handler.value.style.left = _x + 'px'
      handerLeft.value = _x + 'px'
      progressBar.value.style.width = _x + 'px'
    } else if (_x > props.width - props.height) {
      handler.value.style.left = props.width - props.height + 'px'
      handerLeft.value = props.width - props.height + 'px'
      progressBar.value.style.width = props.width + 'px'
      passVerify()
    }
  }
}
const dragFinish = (e: any) => {
  dragVerify.value!.onselectstart = function () {
    return false
  }
  if (isMoving.value && !props.isPassing) {
    const _x = (e.pageX || e.changedTouches[0].pageX) - x.value
    if (_x < props.width - props.height) {
      isOk.value = true
      setTimeout(function () {
        handler.value.style.left = '0'
        handerLeft.value = '0'
        progressBar.value.style.width = '0'
        isOk.value = false
      }, 500)
    } else {
      handler.value.style.left = props.width - props.height + 'px'
      handerLeft.value = props.width - props.height + 'px'
      progressBar.value.style.width = props.width + 'px'
      passVerify()
    }
    isMoving.value = false
  }
}
const passVerify = () => {
  isMoving.value = false
  icon.value = 1
  progressBar.value.style.background = props.completedBg
  // messageRef.value.style['-webkit-text-fill-color'] = 'unset'
  messageRef.value.style.setProperty('-webkit-text-fill-color', 'unset')
  messageRef.value.style.animation = 'slidetounlock2 3s infinite'
  messageRef.value.style.color = '#fff'
  emit('update:isPassing', true)
  emit('passcallback')
}

// 复原滚动滑块
const restore = () => {
  progressBar.value.style.background = props.completedBg
  handler.value.style.left = '0'
  handerLeft.value = '0'
  progressBar.value.style.width = '0'
  isOk.value = false
  icon.value = 0
  messageRef.value.style.setProperty('-webkit-text-fill-color', 'transparent')
  // messageRef.value.style['-webkit-text-fill-color'] = 'transparent'
  messageRef.value.style.color = props.textColor
  messageRef.value.style.animation = 'slidetounlock 3s infinite'
}
</script>
<style scoped>
.drag_verify {
  position: relative;
  overflow: hidden;
  text-align: center;
  background-color: #e8e8e8;
}
.drag_verify .dv_handler {
  box-sizing: border-box;
  position: absolute;
  top: 0;
  left: 0;
  cursor: move;
  border: 1px solid rgba(211, 214, 219, 1);
}
.drag_verify .dv_handler i {
  padding-left: 0;
  font-size: 16px;
  color: #666666;
}
.drag_verify .dv_handler .el-icon-circle-check {
  margin-top: 9px;
  color: #66cc66;
}
.drag_verify .dv_progress_bar {
  position: absolute;
  width: 0;
  height: 34px;
}
.drag_verify .dv_text {
  position: absolute;
  top: 0;
  color: transparent;
  user-select: none;
  background: -webkit-gradient(
    linear,
    left top,
    right top,
    color-stop(0, var(--text-color)),
    color-stop(0.4, var(--text-color)),
    color-stop(0.5, #ffffff),
    color-stop(0.6, var(--text-color)),
    color-stop(1, var(--text-color))
  );
  background-clip: text;
  animation: slidetounlock 3s infinite;
  -webkit-text-fill-color: transparent;
  text-size-adjust: none;
}
.drag_verify .dv_text * {
  -webkit-text-fill-color: var(--text-color);
}
.goFirst {
  left: 0 !important;
  transition: left 0.5s;
}
.goFirst2 {
  width: 0 !important;
  transition: width 0.5s;
}
</style>
<style>
@keyframes slidetounlock {
  0% {
    background-position: var(--pwidth) 0;
  }
  100% {
    background-position: var(--width) 0;
  }
}

@keyframes slidetounlock2 {
  0% {
    background-position: var(--pwidth) 0;
  }
  100% {
    background-position: var(--pwidth) 0;
  }
}
</style>
